package bb.lanxing.manager;

import android.location.GnssStatus;
import android.location.GpsStatus;
import android.util.Log;

import java.io.IOException;

import bb.lanxing.App;
import bb.lanxing.calc.calculator.BiketrainerCalc;
import bb.lanxing.calc.calculator.CadenceCalc;
import bb.lanxing.calc.calculator.CrosstrainerCalc;
import bb.lanxing.calc.calculator.HeartrateCalc;
import bb.lanxing.calc.calculator.IndoorbikeCalc;
import bb.lanxing.calc.calculator.PowerrateCalc;
import bb.lanxing.calc.calculator.RowerCalc;
import bb.lanxing.calc.data.BiketrainerPoint;
import bb.lanxing.calc.data.CadencePoint;
import bb.lanxing.calc.data.CrosstrainerPoint;
import bb.lanxing.calc.data.GpsPoint;
import bb.lanxing.calc.data.HeartratePoint;
import bb.lanxing.calc.data.IndoorbikePoint;
import bb.lanxing.calc.data.PowerratePoint;
import bb.lanxing.calc.data.RowerPoint;
import bb.lanxing.calc.data.SourcePoint;
import bb.lanxing.lib.devices.antplus.AntPlusDataDispatcher;
import bb.lanxing.lib.devices.api.ConnectionListener;
import bb.lanxing.lib.devices.api.DeviceManager;
import bb.lanxing.lib.devices.api.SmartDevice;
import bb.lanxing.lib.devices.base.DeviceContext;
import bb.lanxing.lib.devices.base.converter.BiketrainerConverter;
import bb.lanxing.lib.devices.base.converter.Cadence01Converter;
import bb.lanxing.lib.devices.base.converter.CadenceConverter;
import bb.lanxing.lib.devices.base.converter.CrosstrainerConverter;
import bb.lanxing.lib.devices.base.converter.HeartrateConverter;
import bb.lanxing.lib.devices.base.converter.IndoorbikeConverter;
import bb.lanxing.lib.devices.base.converter.PowerrateConverter;
import bb.lanxing.lib.devices.base.converter.RowerConverter;
import bb.lanxing.lib.devices.bici.BiciController;
import bb.lanxing.lib.devices.bici.cmd.CyclingCMD;
import bb.lanxing.lib.devices.utils.DeviceManagerHelper;
import bb.lanxing.model.database.Device;
import bb.lanxing.model.database.Workout;

public class SourcePointManager {
    private static final String TAG = "SourcePointManager";

    public static final int USE_GNSS_CALLBACK = 5;
    private static final int WORKOUT_TIME_INTERVAL_NORMAL = 60000;
    private static final int WORKOUT_TIME_INTERVAL_SUPER = 5000;

    private static volatile SourcePointManager instance;

    private SourcePoint biciSourcePoint;
    private SourcePoint sourcePoint;

    private CadencePoint cadencePoint;
    private GpsPoint gpsPoint;
    public HeartratePoint heartratePoint;
    public PowerratePoint powerratePoint;
    public BiketrainerPoint biketrainerPoint;
    public IndoorbikePoint indoorbikePoint;
    public CrosstrainerPoint crosstrainerPoint;
    public RowerPoint rowerPoint;

    private CadenceCalc cadenceCalc;
    public HeartrateCalc heartrateCalc;
    public PowerrateCalc powerrateCalc;
    public BiketrainerCalc biketrainerCalc;
    public IndoorbikeCalc indoorbikeCalc;
    public CrosstrainerCalc crosstrainerCalc;
    public RowerCalc rowerCalc;

    private int stepOffset;
    private int steps;
    private long lastStopByHandTime = 0;

    public final CadenceConverter cadenceConverter = new CadenceDataListener();
    public final Cadence01Converter cadence01Converter = new Cadence01DataListener();
    public final HeartrateConverter heartrateConverter = new HeartrateDataListener();
    public final PowerrateConverter powerrateConverter = new PowerrateDataListener();
    public final BiketrainerConverter biketrainerConverter = new BiketrainerDataListener();
    public final IndoorbikeConverter indoorbikeConverter = new IndoorbikeDataListener();
    public final CrosstrainerConverter crosstrainerConverter = new CrosstrainerDataListener();
    public final RowerConverter rowerConverter = new RowerDataListener();

    public final HeartrateConverter heartRate01Converter = new Heartrate01DataListener();

    private SystemLocationManager.GpsChangedListener mGpsChangedListener = new SystemLocationManager.GpsChangedListener() {
        @Override
        public void onGpsStatusChanged(int event, GpsStatus status, GnssStatus gnssStatus) {
        }

        @Override
        public void onGpsLocationChanged(GpsPoint gpsPoint) {
            setGpsPoint(gpsPoint);
        }
    };

    public final ConnectionListener deviceListener = new ConnectionListener() {
        @Override
        public void onConnectionStateChanged(SmartDevice device, int newsState, int error) {
            if (newsState == DeviceManager.STATE_CONNECTED) {
                onDeviceConnected(device);
            } else if (newsState == DeviceManager.STATE_DISCONNECTED) {
                onDeviceDisconnected(device);
            }
        }

        public void onDeviceConnected(SmartDevice device) {
            Log.d(TAG, "onDeviceConnected, type = " + device.getType());
            int type = device.getType();
            switch (type) {
                case SmartDevice.TYPE_BICI -> {
                    BiciController biciController = DeviceManagerHelper.getBiciController();
                    if (biciController != null) {
                        biciController.registerBiciListener(biciListener);
                    }
                }
                case SmartDevice.TYPE_CADENCE, SmartDevice.TYPE_VORTEX_CADENCE, SmartDevice.TYPE_CADENCE01,
                     SmartDevice.TYPE_Q1 -> {
                    if (cadenceCalc == null) {
                        cadenceCalc = new CadenceCalc();
                        cadencePoint = null;
                    }
                }
                case SmartDevice.TYPE_HEARTRATE, SmartDevice.TYPE_HEARTRATE_BELT, SmartDevice.TYPE_HEART_RATE01  -> {
                    if (heartrateCalc == null) {
                        heartratePoint = null;
                        heartrateCalc = new HeartrateCalc();
                    }
                }
                case SmartDevice.TYPE_POWERRATE -> {
                    if (powerrateCalc == null) {
                        powerratePoint = null;
                        powerrateCalc = new PowerrateCalc();
                    }
                }

                case SmartDevice.TYPE_BIKE_TRAINER -> {
                    if (biketrainerCalc == null) {
                        biketrainerPoint = null;
                        biketrainerCalc = new BiketrainerCalc();
                    }
                }
                case SmartDevice.TYPE_INDOOR_BIKE -> {
                    if (indoorbikeCalc == null) {
                        indoorbikePoint = null;
                        indoorbikeCalc = new IndoorbikeCalc();
                    }
                }
                case SmartDevice.TYPE_CROSS_TRAINER -> {
                    if (crosstrainerCalc == null) {
                        crosstrainerPoint = null;
                        crosstrainerCalc = new CrosstrainerCalc();
                    }
                }

                case SmartDevice.TYPE_ROWER -> {
                    if (rowerCalc == null) {
                        rowerPoint = null;
                        rowerCalc = new RowerCalc();
                    }
                }
                default -> Log.w(TAG, "onDeviceConnected: not handled device type!");
            }
        }

        public void onDeviceDisconnected(SmartDevice device) {
            Log.d(TAG, "onDeviceDisconnected, type = " + device.getType());
            DeviceManager deviceManager = DeviceContext.getDeviceManager();
            int type = device.getType();
            switch (type) {
                case SmartDevice.TYPE_BICI -> {
                    BiciController biciController = DeviceManagerHelper.getBiciController();
                    if (biciController != null) {
                        biciController.unregisterBiciListener(biciListener);
                    }
                }
                case SmartDevice.TYPE_CADENCE, SmartDevice.TYPE_VORTEX_CADENCE, SmartDevice.TYPE_CADENCE01,
                     SmartDevice.TYPE_Q1 -> {
                    if (deviceManager != null && deviceManager.isConnected(SmartDevice.TYPE_CADENCE) && deviceManager.isConnected(SmartDevice.TYPE_VORTEX_CADENCE)) {
                        return;
                    }
                    cadencePoint = null;
                    if (sourcePoint != null && gpsPoint != null) {
                        sourcePoint.setGpsPoint(gpsPoint);
                    }
                    if (cadenceCalc != null) {
                        cadenceCalc.release();
                        cadenceCalc = null;
                    }
                }
                case SmartDevice.TYPE_HEARTRATE, SmartDevice.TYPE_HEARTRATE_BELT, SmartDevice.TYPE_HEART_RATE01 -> {
                    heartratePoint = null;
                    if (heartrateCalc != null) {
                        heartrateCalc.release();
                        heartrateCalc = null;
                    }
                }

                case SmartDevice.TYPE_POWERRATE -> {
                    powerratePoint = null;
                    if (powerrateCalc != null) {
                        powerrateCalc.release();
                        powerrateCalc = null;
                    }
                }

                case SmartDevice.TYPE_BIKE_TRAINER -> {
                    biketrainerPoint = null;
                    if (biketrainerCalc != null) {
                        biketrainerCalc.release();
                        biketrainerCalc = null;
                    }
                }

                case SmartDevice.TYPE_INDOOR_BIKE -> {
                    indoorbikePoint = null;
                    if (indoorbikeCalc != null) {
                        indoorbikeCalc.release();
                        indoorbikeCalc = null;
                    }
                }

                case SmartDevice.TYPE_CROSS_TRAINER -> {
                    crosstrainerPoint = null;
                    if (crosstrainerCalc != null) {
                        crosstrainerCalc.release();
                        crosstrainerCalc = null;
                    }
                }

                case SmartDevice.TYPE_ROWER -> {
                    rowerPoint = null;
                    if (rowerCalc != null) {
                        rowerCalc.release();
                        rowerCalc = null;
                    }
                }
                default -> Log.w(TAG, "onDeviceDisconnected: not handled device type!");
            }
        }
    };
    public final BiciController.BiciListener biciListener = new BiciController.BiciListener() {
        @Override
        public void onCmdStatus(int cmd, int status) {
        }

        @Override
        public void onConnectionStateChanged(SmartDevice device, int newsState, int error) {
        }

        @Override
        public void onGetFile(String filePath) {
        }

        @Override
        public void onProgressUpdate(int cmd, int progress) {
        }

        @Override
        public void onPackage(int cmdId, byte[] data) {
            if (cmdId == USE_GNSS_CALLBACK) {
                onBiciCyclingData(new CyclingCMD(data));
            }
        }
    };
    private final StepCounterManager.StepChangedListener stepChangedListener = step -> {
        SourcePointManager sourcePointManager = SourcePointManager.this;
        sourcePointManager.steps = sourcePointManager.stepOffset + step;
    };

    private SourcePointManager() {
    }

    public static SourcePointManager getInstance() {
        if (instance == null) {
            synchronized (SourcePointManager.class) {
                if (instance == null) {
                    instance = new SourcePointManager();
                }
            }
        }
        return instance;
    }

    public static void terminate() {
        if (instance != null) {
            instance.release();
            instance = null;
        }
    }

    public void release() {
        gpsPoint = null;
        cadencePoint = null;
        heartratePoint = null;
        powerratePoint = null;
        indoorbikePoint = null;
        crosstrainerPoint = null;
        sourcePoint = null;
        biciSourcePoint = null;
        if (cadenceCalc != null) {
            cadenceCalc.release();
        }
        if (heartrateCalc != null) {
            heartrateCalc.release();
        }

        if (powerrateCalc != null) {
            powerrateCalc.release();
        }

        if (biketrainerCalc != null) {
            biketrainerCalc.release();
        }
        if (indoorbikeCalc != null) {
            indoorbikeCalc.release();
        }

        if (crosstrainerCalc != null) {
            crosstrainerCalc.release();
        }

        if (rowerCalc != null) {
            rowerCalc.release();
        }

        BiciController biciController = DeviceManagerHelper.getBiciController();
        if (biciController != null) {
            biciController.unregisterBiciListener(biciListener);
        }
        StepCounterManager.release();
        steps = 0;
        stepOffset = 0;
        lastStopByHandTime = 0L;
    }

    public boolean openSystemGps() {
        try {
            if (SystemLocationManager.getInstance().openSystemGps()) {
                SystemLocationManager.getInstance().registerGpsChangedListener(mGpsChangedListener);
                return true;
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return false;
    }

    public void closeSystemGps() {
        //Log.logi(TAG, "closeSystemGps");
        SystemLocationManager.getInstance().unregisterGpsChangedListener(mGpsChangedListener);
        SystemLocationManager.getInstance().closeSystemGps();
        SystemLocationManager.terminate();
        gpsPoint = null;
    }

    public boolean openStepSensor(int stepOffset) {
        if (StepCounterManager.getInstance().openCounter()) {
            this.stepOffset = stepOffset;
            steps = 0;
            StepCounterManager.getInstance().registerListener(stepChangedListener);
            return true;
        }
        return false;
    }

    public void closeStepSensor() {
        StepCounterManager.getInstance().closeCounter();
        StepCounterManager.getInstance().unregisterListener(stepChangedListener);
    }

    public void setSourcePoint(SourcePoint sourcePoint) {
        this.sourcePoint = sourcePoint;
    }

    public SourcePoint getSourcePoint() {
        if (!isPointChanged(sourcePoint)) {
            if (sourcePoint != null) {
                sourcePoint.setIsOldPoint(true);
            }
            return sourcePoint;
        }
        Log.v(TAG, "getSourcePoint, Point Changed");
        sourcePoint = new SourcePoint();
        sourcePoint.setGpsPoint(gpsPoint);
        sourcePoint.setCadencePoint(cadencePoint);
        sourcePoint.setPowerratePoint(powerratePoint);
        sourcePoint.setBiketrainerPoint(biketrainerPoint);
        sourcePoint.setHeartratePoint(heartratePoint);
        sourcePoint.setIndoorbikePoint(indoorbikePoint);
        sourcePoint.setCrosstrainerPoint(crosstrainerPoint);
        sourcePoint.setRowerPoint(rowerPoint);
        sourcePoint.setSteps(steps);

        if (indoorbikePoint != null) {
            if (indoorbikePoint.getIndoorbikePower() > 0) {
                sourcePoint.setPower(indoorbikePoint.getIndoorbikePower());
            }
        }

        if (crosstrainerPoint != null) {
            if (crosstrainerPoint.getCrosstrainerPower() > 0) {
                sourcePoint.setPower(crosstrainerPoint.getCrosstrainerPower());
            }
        }

        if (rowerPoint != null) {
            if (rowerPoint.getRowerPower() > 0) {
                sourcePoint.setPower(rowerPoint.getRowerPower());
            }
        }

        if (powerratePoint != null) {
            if (powerratePoint.getPowerrate() > 0) {
                sourcePoint.setPower(powerratePoint.getPowerrate());
            }
        }

        if (biketrainerPoint != null) {
            if (biketrainerPoint.getBiketrainerPower() > 0) {
                sourcePoint.setPower(biketrainerPoint.getBiketrainerPower());
            }
        }
        return sourcePoint;
    }

    public synchronized SourcePoint getBiciSourcePoint() {
        return biciSourcePoint;
    }

    public void setGpsPoint(GpsPoint gpsPoint) {
        this.gpsPoint = gpsPoint;
    }

    private boolean isPointChanged(SourcePoint lastSourcePoint) {
        int lastSteps;
        CadencePoint lastCadence;
        HeartratePoint lastHeartrate;
        PowerratePoint lastPowerrate;
        BiketrainerPoint lastBiketrainer;
        IndoorbikePoint lastIndoorbike;
        CrosstrainerPoint lastCrosstrainer;
        RowerPoint lastRower;

        GpsPoint lastGps = null;
        if (lastSourcePoint != null) {
            lastGps = lastSourcePoint.getGpsPoint();
            lastCadence = lastSourcePoint.getCadencePoint();
            lastHeartrate = lastSourcePoint.getHeartratePoint();
            lastPowerrate = lastSourcePoint.getPowerratePoint();
            lastBiketrainer = lastSourcePoint.getBiketrainerPoint();
            lastIndoorbike = lastSourcePoint.getIndoorbikePoint();
            lastCrosstrainer = lastSourcePoint.getCrosstrainerPoint();
            lastRower = lastSourcePoint.getRowerPoint();
            lastSteps = lastSourcePoint.getSteps();
        } else {
            lastSteps = -1;
            lastCadence = null;
            lastHeartrate = null;
            lastPowerrate = null;
            lastBiketrainer = null;
            lastIndoorbike = null;
            lastCrosstrainer = null;
            lastRower = null;
        }

        if ((this.gpsPoint != null && !this.gpsPoint.equals(lastGps))
                || (this.cadencePoint != null && !this.cadencePoint.equals(lastCadence))
                || (this.powerratePoint != null && !this.powerratePoint.equals(lastPowerrate))
                || (this.biketrainerPoint != null && !this.biketrainerPoint.equals(lastBiketrainer))
                || (this.indoorbikePoint != null && !this.indoorbikePoint.equals(lastIndoorbike))
                || (this.crosstrainerPoint != null && !this.crosstrainerPoint.equals(lastCrosstrainer))
                || (this.rowerPoint != null && !this.rowerPoint.equals(lastRower))
                || (this.heartratePoint != null && !this.heartratePoint.equals(lastHeartrate))
                || this.steps != lastSteps) {
            Log.d(TAG, "isPointChanged point changed...");
            return true;
        }
        return false;
    }

    public void onBiciCyclingData(CyclingCMD cyclingCMD) {
        if (System.currentTimeMillis() - lastStopByHandTime < (!App.getContext().isSuperVersion() ? WORKOUT_TIME_INTERVAL_NORMAL : WORKOUT_TIME_INTERVAL_SUPER)) {
            return;
        }
        lastStopByHandTime = 0L;
        convertBiciCyclingData(cyclingCMD);
        App.getContext().uploadBiciLocationWithPhone(false);
    }

    private void convertBiciCyclingData(CyclingCMD data) {
        byte b;
        int i;
        int i2;
        int i3;
        double d;
        if (data == null || data.getCumulativewheel() <= 0) {
            return;
        }
        long currentTimeMillis = System.currentTimeMillis();
        double lon = (data.getLon() * 1.0d) / 1000000.0d;
        double lat = (data.getLat() * 1.0d) / 1000000.0d;
        double alt = data.getAlt() / 100.0d;
        int cumulativecrank = data.getCumulativecrank();
        int cumulativewheel = data.getCumulativewheel();
        short wheel = data.getWheel();
        short crank = data.getCrank();
        int duration = data.getDuration();
        int distance = (int) (data.getDistance() * 1.593f);
        byte heartrate = data.getHeartrate();
        data.getFlag();
        int i4 = crank <= 0 ? 0 : 60000 / crank;
        if (wheel <= 0) {
            b = heartrate;
            i = 0;
        } else {
            b = heartrate;
            i = 60000 / wheel;
        }
        if (wheel <= 0) {
            i2 = duration;
            i3 = distance;
            d = 0.0d;
        } else {
            i2 = duration;
            i3 = distance;
            d = 1.593f * (1000.0f / wheel);
        }
        if (i4 > 256) {
            i4 = 256;
        }
        if (i4 < 0) {
            i4 = 0;
        }
        GpsPoint gpsPoint = new GpsPoint();
        gpsPoint.setLatitude(lon);
        gpsPoint.setLongitude(lat);
        gpsPoint.setAltitude(alt);
        gpsPoint.setTimestamp(currentTimeMillis);
        gpsPoint.setSpeed(data.getSpeed());
        gpsPoint.setSource(Workout.LOCATION_SOURCE_BICI);
        CadencePoint cadencePoint = new CadencePoint();
        cadencePoint.setSumWheel(cumulativewheel);
        cadencePoint.setSumCadence(cumulativecrank);
        cadencePoint.setCadence(i4);
        cadencePoint.setWheelRpm(i);
        cadencePoint.setSpeed(d);
        cadencePoint.setSumDuration(i2);
        cadencePoint.setSumDistance(i3);
        cadencePoint.setSource(Workout.CADENCE_SOURCE_BICI);
        HeartratePoint heartratePoint = new HeartratePoint();
        heartratePoint.setHeartrate(b);
        heartratePoint.setSource(Workout.HEARTRATE_SOURCE_BICI);
        synchronized (this) {
            SourcePoint sourcePoint = new SourcePoint();
            biciSourcePoint = sourcePoint;
            sourcePoint.setGpsPoint(gpsPoint);
            biciSourcePoint.setCadencePoint(cadencePoint);
            biciSourcePoint.setHeartratePoint(heartratePoint);
            biciSourcePoint.setSpeed(d);
        }
    }

    private class CadenceDataListener extends CadenceConverter implements AntPlusDataDispatcher.OnAntPlusCandenceListener {
        private CadenceDataListener() {
        }

        @Override
        public void onCadenceData(int deviceType, int sumWheel, int wheelTime, int sumCadence, int cadenceTime, int pressure, int temperature) {
            Log.d(TAG, "onCadenceData, sumWheel = " + sumWheel + ", wheelTime = " + wheelTime + ", sumCadence = " + sumCadence + ", cadenceTime = " + cadenceTime + ", pressure = " + pressure + ", temperature = " + temperature);
            CadencePoint cadencePoint = new CadencePoint();
            cadencePoint.setSumWheel(sumWheel);
            cadencePoint.setWheelTime(wheelTime);
            cadencePoint.setSumCadence(sumCadence);
            cadencePoint.setCadenceTime(cadenceTime);
            cadencePoint.setPressure(pressure);
            cadencePoint.setTemperature(temperature);
            if (deviceType == Device.TYPE_Q1) {
                cadencePoint.setSource(Workout.CADENCE_SOURCE_QI);
            } else if (deviceType == Device.TYPE_BICI) {
                cadencePoint.setSource(Workout.CADENCE_SOURCE_BICI);
            } else if (deviceType == Device.TYPE_IGPS) {
                cadencePoint.setSource(Workout.CADENCE_SOURCE_IGPS);
            } else if (deviceType == Device.TYPE_BRYTEN) {
                cadencePoint.setSource(Workout.CADENCE_SOURCE_BRYTON);
            } else {
                cadencePoint.setSource(Workout.CADENCE_SOURCE_BLE);
            }
            if (cadenceCalc == null || cadenceCalc.calc(cadencePoint, false)) {
                setCadencePoint(cadencePoint);
            }
        }

        @Override
        public void onCadenceData(int deviceType, int cadenceRpm, int speed) {
            CadencePoint cadencePoint = new CadencePoint();
            cadencePoint.setCadence(cadenceRpm);
            cadencePoint.setSpeed(speed);
            cadencePoint.setSource(Workout.CADENCE_SOURCE_BLE);
            setCadencePoint(cadencePoint);
        }
    }

    private void setCadencePoint(CadencePoint cadencePoint) {
        this.cadencePoint = cadencePoint;
    }


    private class Cadence01DataListener extends Cadence01Converter implements AntPlusDataDispatcher.OnAntPlusCandenceListener {
        private Cadence01DataListener() {
        }

        @Override
        public void onCadenceData(int deviceType, int sumWheel, int wheelTime, int sumCadence, int cadenceTime, int pressure, int temperature) {
            Log.d(TAG, "onCadence01Data, sumWheel = " + sumWheel + ", wheelTime = " + wheelTime + ", sumCadence = " + sumCadence + ", cadenceTime = " + cadenceTime + ", pressure = " + pressure + ", temperature = " + temperature);
            CadencePoint cadencePoint = new CadencePoint();
            cadencePoint.setSumWheel(sumWheel);
            cadencePoint.setWheelTime(wheelTime);
            cadencePoint.setSumCadence(sumCadence);
            cadencePoint.setCadenceTime(cadenceTime);
            cadencePoint.setPressure(pressure);
            cadencePoint.setTemperature(temperature);
            cadencePoint.setSource(Workout.CADENCE_SOURCE_BLE);
            if (cadenceCalc == null || cadenceCalc.calc(cadencePoint, true)) {
                setCadencePoint(cadencePoint);
            }
        }

        @Override
        public void onCadenceData(int deviceType, int cadenceRpm, int speed) {
            CadencePoint cadencePoint = new CadencePoint();
            cadencePoint.setCadence(cadenceRpm);
            cadencePoint.setSpeed(speed);
            cadencePoint.setSource(Workout.CADENCE_SOURCE_BLE);
            setCadencePoint(cadencePoint);
        }
    }

    private class HeartrateDataListener extends HeartrateConverter implements AntPlusDataDispatcher.OnAntPlusHeartrateListener {
        private HeartrateDataListener() {
        }

        @Override
        public void onHeartrate(int deviceType, int heartrate) {
            Log.v(TAG, "onHeartrate, heartrate = " + heartrate);
            HeartratePoint heartratePoint = new HeartratePoint();
            heartratePoint.setHeartrate(heartrate);
            if (deviceType == Device.TYPE_BICI) {
                heartratePoint.setSource(Workout.HEARTRATE_SOURCE_BICI);
            } else if (deviceType == Device.TYPE_IGPS) {
                heartratePoint.setSource(Workout.HEARTRATE_SOURCE_IGPS);
            } else if (deviceType == Device.TYPE_BRYTEN) {
                heartratePoint.setSource(Workout.HEARTRATE_SOURCE_BRYTON);
            } else if (deviceType == Device.TYPE_HR_X2_PRO) {
                heartratePoint.setSource(Workout.HEARTRATE_SOURCE_XOSS_X2P);
            } else {
                heartratePoint.setSource(Workout.HEARTRATE_SOURCE_BLE);
            }
            if (heartrateCalc != null) {
                heartrateCalc.calc(heartratePoint);
            }
            SourcePointManager.this.heartratePoint = heartratePoint;
        }
    }

    private class Heartrate01DataListener extends HeartrateConverter implements AntPlusDataDispatcher.OnAntPlusHeartrateListener {
        private Heartrate01DataListener() {
        }

        @Override
        public void onHeartrate(int deviceType, int heartrate) {
            Log.v(TAG, "onHeartrate, heartrate = " + heartrate);
            HeartratePoint heartratePoint = new HeartratePoint();
            heartratePoint.setHeartrate(heartrate);
            heartratePoint.setSource(Workout.HEARTRATE_SOURCE_BLE);
            if (heartrateCalc != null) {
                heartrateCalc.calc01(heartratePoint);
            }
            SourcePointManager.this.heartratePoint = heartratePoint;
        }
    }

    private class PowerrateDataListener extends PowerrateConverter implements AntPlusDataDispatcher.OnAntPlusPowerrateListener {
        private PowerrateDataListener() {
        }

        @Override
        public void onPowerrate(int deviceType, int powerrate) {
            PowerratePoint powerratePoint = new PowerratePoint();
            powerratePoint.setPowerrate(powerrate);
            if (deviceType == Device.TYPE_POWERRATE) {
                powerratePoint.setSource(Workout.POWER_SOURCE_OTHER);
            } else {
                powerratePoint.setSource(Workout.POWER_SOURCE_OTHER);
            }
            if (powerrateCalc != null) {
                powerrateCalc.calc(powerratePoint);
            }
            SourcePointManager.this.powerratePoint = powerratePoint;
        }
    }

    private class BiketrainerDataListener extends BiketrainerConverter implements AntPlusDataDispatcher.OnAntPlusBiketrainerListener {
        private BiketrainerDataListener() {
        }

        @Override

        public void onBiketrainer(int deviceType, int power, int crank, int time) {
            BiketrainerPoint biketrainerPoint = new BiketrainerPoint();
            biketrainerPoint.setBiketrainerPower(power);
            biketrainerPoint.setBiketrainerCrank(crank);
            biketrainerPoint.setBiketrainerEventTime(time);
            biketrainerPoint.setSource(Workout.POWER_SOURCE_OTHER);

            if (biketrainerCalc != null) {
                biketrainerCalc.calc(biketrainerPoint);
            }
            SourcePointManager.this.biketrainerPoint = biketrainerPoint;
        }
    }

    private class IndoorbikeDataListener extends IndoorbikeConverter implements AntPlusDataDispatcher.OnAntPlusIndoorbikeListener {
        private IndoorbikeDataListener() {
        }

        // @Override
        public void onIndoorbike(int deviceType, double doubleValueSpeed, int intValueCadence, int intValuePower, int intValueResistanceLevel, int intValueEnergy, double doubleValueTotalDistance, int intValueHeartRate) {
            IndoorbikePoint indoorbikePoint = new IndoorbikePoint();
            indoorbikePoint.setIndoorbikeSpeed(doubleValueSpeed);
            indoorbikePoint.setIndoorbikeCadence(intValueCadence);
            indoorbikePoint.setIndoorbikePower(intValuePower);
            indoorbikePoint.setIndoorbikeResistanceLevel(intValueResistanceLevel);
            indoorbikePoint.setIndoorbikeEnergy(intValueEnergy);
            indoorbikePoint.setIndoorbikeTotalDistance(doubleValueTotalDistance);
            indoorbikePoint.setIndoorbikeHeartRate(intValueHeartRate);

            //Log.v(TAG, "onIndoorbike, doubleValueSpeed = " + doubleValueSpeed);
            //Log.v(TAG, "onIndoorbike, intValueCadence = " + intValueCadence);
            //Log.v(TAG, "onIndoorbike, intValuePower = " + intValuePower);
            //Log.v(TAG, "onIndoorbike, intValueResistanceLevel = " + intValueResistanceLevel);
            //Log.v(TAG, "onIndoorbike, intValueEnergy = " + intValueEnergy);
            //Log.v(TAG, "onIndoorbike, intValueHeartRate = " + intValueHeartRate);

            if (deviceType == Device.TYPE_INDOOR_BIKE) {
                indoorbikePoint.setSource(Workout.INDOORBIKE_SOURCE_OTHER);
            } else {
                indoorbikePoint.setSource(Workout.INDOORBIKE_SOURCE_OTHER);
            }

            if (indoorbikeCalc != null) {
                indoorbikeCalc.calc(indoorbikePoint);
            }
            SourcePointManager.this.indoorbikePoint = indoorbikePoint;
        }
    }

    private class CrosstrainerDataListener extends CrosstrainerConverter implements AntPlusDataDispatcher.OnAntPlusCrosstrainerListener {
        private CrosstrainerDataListener() {
        }

        // @Override
        public void onCrosstrainer(int deviceType, double doubleValueSpeed, double doubleValueTotalDistance, int intValueStepPerMinute, int intValueStrideCount, int intValueResistanceLevel, int intValuePower, int intValueEnergy) {
            CrosstrainerPoint crosstrainerPoint = new CrosstrainerPoint();
            crosstrainerPoint.setCrosstrainerSpeed(doubleValueSpeed);
            crosstrainerPoint.setCrosstrainerStride(intValueStrideCount);
            crosstrainerPoint.setCrosstrainerStepRate(intValueStepPerMinute);
            crosstrainerPoint.setCrosstrainerPower(intValuePower);
            crosstrainerPoint.setCrosstrainerResistanceLevel(intValueResistanceLevel);
            crosstrainerPoint.setCrosstrainerEnergy(intValueEnergy);
            crosstrainerPoint.setCrosstrainerTotalDistance(doubleValueTotalDistance);

            Log.v(TAG, "onCrosstrainer, doubleValueSpeed = " + doubleValueSpeed);
            Log.v(TAG, "onCrosstrainer, intValuePower = " + intValuePower);
            Log.v(TAG, "onCrosstrainer, intValueResistanceLevel = " + intValueResistanceLevel);
            Log.v(TAG, "onCrosstrainer, intValueEnergy = " + intValueEnergy);
            Log.v(TAG, "onCrosstrainer, intValueStrideCount = " + intValueStrideCount);
            Log.v(TAG, "onCrosstrainer, intValueStepPerMinute = " + intValueStepPerMinute);
            Log.v(TAG, "onCrosstrainer, doubleValueTotalDistance = " + doubleValueTotalDistance);

            if (deviceType == Device.TYPE_CROSS_TRAINER) {
                crosstrainerPoint.setSource(Workout.CROSSTRAINER_SOURCE_OTHER);
            }

            if (crosstrainerCalc != null) {
                crosstrainerCalc.calc(crosstrainerPoint);
            }
            SourcePointManager.this.crosstrainerPoint = crosstrainerPoint;
        }
    }

    private class RowerDataListener extends RowerConverter implements AntPlusDataDispatcher.OnAntPlusRowerListener {
        private RowerDataListener() {
        }

        public void onRower(int deviceType, int intValueStrokeRate, int intValueStrokeCount, int intValueAvgStrokeRate, double doubleValueTotalDistance, double doubleValuePace, int intValuePower, int intValueResistanceLevel, int intValueEnergy) {
            RowerPoint rowerPoint = new RowerPoint();
            rowerPoint.setRowerStrokeRate(intValueStrokeRate);
            rowerPoint.setRowerStrokeCount(intValueStrokeCount);
            rowerPoint.setRowerAvgStrokeRate(intValueAvgStrokeRate);
            rowerPoint.setRowerTotalDistance(doubleValueTotalDistance);
            rowerPoint.setRowerPace(doubleValuePace);
            rowerPoint.setRowerPower(intValuePower);
            rowerPoint.setRowerResistanceLevel(intValueResistanceLevel);
            rowerPoint.setRowerEnergy(intValueEnergy);

            if (deviceType == Device.TYPE_ROWER) {
                rowerPoint.setSource(Workout.ROWER_SOURCE_OTHER);
            }

            if (rowerCalc != null) {
                rowerCalc.calc(rowerPoint);
            }
            SourcePointManager.this.rowerPoint = rowerPoint;
        }
    }
}